package paws.core

import scala.actors.Actor
import util.SimulationUtils._
import Actor._
import NodeType._

class Simulation extends scala.actors.Actor {
  // private var area: (Double, Double) = (100, 100)
  private var nodes: Set[Node] = Set()
  private var running = false
  private var me: Simulation = null
  private var router = new Router
  
  var simData: List[Data] = Nil
  
  var log: Logger = null
  var elog: Logger = null
  
  private
  def addData(d: Data) = { simData = d :: simData }
  def getData() = 
    if(running)
      Nil
    else
      simData
  
  def getNodes = nodes
  def getNodeCount = nodes.size
  
  def getSourceNodes = nodes.filter(_.getNodeType == Source)
  def getIntermediaryNodes = nodes.filter(_.getNodeType == Intermediary)
  def getDestinationNodes = nodes.filter(_.getNodeType == Destination)  
  
  private[core]
  def getRouter = router
  
  def addNode(n: Node): Unit = {
    if(!running) {
      nodes = nodes + n
      val p = n.getParameters
      router.addAndLink(n)
    }
    else elog ! "Attempted to add node while simulation running!"
  }
  
  def removeNode(n: Node) = {
    if(!running)
      nodes = nodes - n
    else
      elog ! "Attempted to remove node while simulation running!"
  }
  
  def act {
    me = self.asInstanceOf[Simulation]
    
    // do the simulation
    doSimulation()
    
    // then do orderly shutdown
    log ! "Simulation exiting."    
    nodes.foreach(_ ! ExitNode)             // tell nodes to exit
    var ecount = 0                          // and wait for them to do so
    while(ecount < nodes.size) {
      receive {
        case NodeExited => ecount += 1
      }
    }
    log ! "All nodes exited."
    
    log ! Symbol("exit")                    // terminate the loggers so the JVM
    elog ! Symbol("exit")                   // can exit properly 
    running = false
  }
  
  def doSimulation(): Unit = {
    val maxTicks = 75
    var tickCount = 0
    var tocks = 0
    
    // Let's get the ball rolling...
    nodes.foreach(_ ! Tick(tickCount))
    
    while(tickCount < maxTicks) {        
      receive {
        case Tock(t) =>
          // log ! "Sim got tock " + t + " from " + sender
          tocks += 1
          if(tocks == nodes.size) {
            log ! "Sim got all tocks for tick " + t
            tickCount += 1
            tocks = 0
            if(tickCount != maxTicks)
              nodes.foreach(_ ! Tick(tickCount))
          }
        case d: Data => addData(d)          
      }
    }    
    running = false
  }
  
  def send(msg: Any) = super.send(msg, null)
  
  def isRunning = running
  
  override def start = {
    log =
      {
        val fl = new FileLogger("info", "infolog.txt") with BasicLogger
        val cl = new Logger("info") with BasicLogger
        new ComboLogger("info", fl, cl)
      }
    
    elog =
      {
        val fl = new FileLogger("error", "errlog.txt") with ErrorLogger
        val cl = new Logger("error") with ErrorLogger
        new ComboLogger("error", fl, cl)
      }
    
    log ! "Starting simulation."
    running = true
    nodes.foreach(_.start)    
    super.start
  }  
}